package concurrent;

import java.util.LinkedList;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author wangmaolin1
 * @date 2023/11/17 14:59
 */
public class ProductConsumer {

    public static void main(String[] args) throws InterruptedException {
//        blockQueueProductConsumer();
//        test2();
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        AtomicBoolean flag = new AtomicBoolean(false);
        AtomicInteger c=new AtomicInteger(0);
        new Thread(()->{
            while (true){
                try {
                    lock.lock();
                    while (flag.get()){
                        condition.await();
                    }
                    System.out.println("A");
                    flag.set(true);
                    condition.signal();
                    if (c.incrementAndGet()>=10){
                        break;
                    }
                } catch (InterruptedException e) {

                } finally {
                    lock.unlock();
                }
            }
        }).start();
        new Thread(()->{
           while (true){
               try {
                   lock.lock();
                   while (!flag.get()){
                       condition.await();
                   }
                   System.out.println("B");
                   flag.set(false);
                   condition.signal();
                   if (c.get()>=10){
                       break;
                   }
               } catch (InterruptedException e) {

               } finally {
                   lock.unlock();
               }
           }
        }).start();
    }

    private static void test2() {
        ReentrantLock lock = new ReentrantLock();
        Condition notFull = lock.newCondition();
        Condition notEmpty = lock.newCondition();
        LinkedList<Integer> list = new LinkedList<>();
        new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                lock.lock();
                try {
                    while (list.size() >= 500) {
                        notFull.await();
                    }
                    list.addFirst(i);
                    notEmpty.signal();
                } catch (InterruptedException ignored) {
                } finally {
                    lock.unlock();
                }
            }
        }).start();
        new Thread(() -> {
            while (true) {
                lock.lock();
                try {
                    while (list.size() <= 0) {
                        notEmpty.await();
                    }
                    System.out.println(list.removeFirst());
                    notFull.signal();
                } catch (InterruptedException e) {

                } finally {
                    lock.unlock();
                }

            }
        }).start();
    }

    private static void blockQueueProductConsumer() throws InterruptedException {
        ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(100);
        CountDownLatch c = new CountDownLatch(1000);
        new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                try {
                    queue.put(i);
                } catch (InterruptedException e) {

                }
            }
            queue.offer(99999);
        }).start();
        new Thread(() -> {
            while (true) {
                Integer take = null;
                try {
                    take = queue.take();
                    c.countDown();
                } catch (InterruptedException ignored) {
                }
                if (take != null) {
                    if (take.equals(99999)) {
//                        break;
                    } else {
                        System.out.println(take);

                    }
                }
            }
        }).start();
        c.await();
        System.out.println("end");
    }
}
